package org.pictual.action;

import java.util.Locale;
import java.util.Vector;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.pictual.business.dao.AccesoBD;
import org.pictual.business.dao.exceptions.DAOException;
import org.pictual.business.vo.CompletoVO;
import org.pictual.business.vo.DefinicionVO;
import org.pictual.business.vo.IdiomaVO;
import org.pictual.business.vo.ImagenVO;
import org.pictual.business.vo.PalabraVO;
import org.pictual.controller.DatabaseImg;
import org.pictual.controller.GoogleSearchImg;
import org.pictual.controller.MyImage;
import org.pictual.controller.WikiObtieneDatos;
import org.pictual.controller.WikiTrataDatos;
import org.pictual.controller.mainPackage.Language;
import org.pictual.service.PictualDelegateFactory;
import org.pictual.util.Cache;
import org.pictual.util.GetPronun;
import org.pictual.util.Mail;
import org.pictual.util.RequestKeys;
import org.pictual.util.SessionKeys;

public class SearchAction extends Action{

	protected static Logger log= Logger.getLogger(SearchAction.class);


	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
					throws Exception {

		long t1 = System.currentTimeMillis();
		HttpSession session = request.getSession();
		ServletContext context = getServlet().getServletContext();
		CompletoVO completo = new CompletoVO();
		IdiomaVO idiomaVO = new IdiomaVO();
		DefinicionVO definicionVO = new DefinicionVO();
		PalabraVO palabraVO = new PalabraVO();
		Vector<MyImage> images = new Vector<MyImage>();

		AccesoBD accesoBD = new AccesoBD();

		ImagenVO[] imagenes = new ImagenVO[6];

		String cadena_wiki;
		String query;
		String langLeft;
		String langRight;

		String[] langz={"en", "es", "de", "fr"};

		if(request.getParameter(RequestKeys.LANGUAGE)!=null){
			Locale locale = new Locale(request.getParameter(RequestKeys.LANGUAGE), "");
			request.getSession().setAttribute(org.apache.struts.Globals.LOCALE_KEY,locale);
		}

		boolean enWiki = false;
		boolean enDatabase = false;
		boolean enCache = false;
		boolean descargarImagenes = false;

		boolean nuevaPalabra=false;

		/* OBTENER LOS PARAMETROS DE BUSQUEDA */
		log.info("OBTENER LOS PARAMETROS DE BUSQUEDA");

		query = request.getParameter(RequestKeys.QUERY);
		langLeft = request.getParameter(RequestKeys.FROM);
		langRight = request.getParameter(RequestKeys.TO);

		if(query==null) query=(String) session.getAttribute(SessionKeys.QUERY);
		if(langLeft==null) langLeft=(String) session.getAttribute(SessionKeys.FROM);
		if(langRight==null)langRight=(String) session.getAttribute(SessionKeys.TO);

		//se tratan los parametros
		if(query!=null){
			//			String queryUTF8 = URLEncoder.encode(query, "UTF-8");
			//			query = query.trim().toLowerCase();
			//			query = Codificar.convertir(query);

			//idiomas nulos se predefinen en ingles
			if((langLeft.equals("")) || ((langLeft.equals(null))) ) langLeft="en";
			if (langRight.equals("") || ((langRight.equals(null))) ) langRight="en";

			//se guardan parametros en sesion
			session.setAttribute("left", langLeft);
			session.setAttribute("rigth", langRight);
			session.setAttribute("query", query);

			//claves de idiomas
			int lang1 = Language.resolve(langLeft);
			int lang2 = Language.resolve(langRight);

			//mostramos en log
			log.info("Query: "+query);
			//			log.info("QueryUTF8: "+queryUTF8);
			log.info("Lenguajes: "+lang1+": "+langLeft+"_"+lang1+": "+langRight);


			//			if(!query.contains(" ")) query = queryUTF8;
			//			query = Codificar.removeSpacesForInformation(query);
			//			query = Codificar.cambiar(query);

			String origen = langz[lang1];
			String destino = langz[lang2];
			log.info("Búsqueda: "+query+" with language "+origen +" "+destino);

			/* BUSCAR LA PALABRA EN CACHE */
			log.info("BUSCAR LA PALABRA EN CACHE");

			Cache <String, CompletoVO> cache = (Cache<String, CompletoVO>) context.getAttribute("cache");
			String cadenaParaCache = query+"/"+langLeft+"/"+langRight;

			if(cache == null){
				log.info("CACHE: No existe cache. Se crea");
				cache = new Cache<String, CompletoVO>(100);
				context.setAttribute("cache", cache);
				
				//Se rellena cache
				log.info("Se rellena cache con als mas visitadas");
				String cadena;
				if(accesoBD.conecta()){
					for(CompletoVO palabra: PictualDelegateFactory.getIdiomaDelegate().selectlistadoMasVisitadas(50)){
						cadena=palabra.getPalabra()+
								"/"+Language.resolve(palabra.getIdioma())+
								"/"+Language.resolve(palabra.getWiki());
						cache.put(cadena, palabra);
					}
				}

			}
			log.info("CACHE: Clave de cache: "+cadenaParaCache);

			CompletoVO palabraEnCache = cache.get(cadenaParaCache);
			if (palabraEnCache == null) {
				log.info("CACHE: No esta en cache");

			}else{
				log.info("CACHE: Esta en cache");
				cache.put(cadenaParaCache, palabraEnCache);

				completo = palabraEnCache;

				idiomaVO = completo.getIdiomaVO();
				definicionVO = completo.getDefinicionVO();
				palabraVO = completo.getPalabraVO();
				imagenes = completo.getImagenes();

				/* RECUPERA DATOS EN CACHE */
				log.info("RECUPERA DATOS EN CACHE");
				enCache=true;
			}


			/* NO RECUPERA DATOS EN CACHE */
			if(!enCache){
				log.info("NO RECUPERA DATOS EN CACHE");
				/* BUSCAR EN BASE DE DATOS */
				log.info("BUSCAR EN BASE DE DATOS");
				if(accesoBD.conecta()){

					try {
						completo = PictualDelegateFactory.getIdiomaDelegate().selectPalabraCompleta(query, Language.resolve(langLeft)+1, Language.resolve(langRight)+1);

						if(completo!=null){
							idiomaVO = PictualDelegateFactory.getIdiomaDelegate().readIdioma(query, Language.resolve(langLeft)+1);
							definicionVO = PictualDelegateFactory.getDefinicionDelegate().readDefinicion(idiomaVO.getPalabra_id(), idiomaVO.getIdioma(), Language.resolve(langRight)+1);
							palabraVO = PictualDelegateFactory.getPalabraDelegate().readPalabra(definicionVO.getPalabra_id());
							imagenes[0] = PictualDelegateFactory.getImagenDelegate().readImagen(palabraVO.getImagen_1());
							imagenes[1] = PictualDelegateFactory.getImagenDelegate().readImagen(palabraVO.getImagen_2());
							imagenes[2] = PictualDelegateFactory.getImagenDelegate().readImagen(palabraVO.getImagen_3());
							imagenes[3] = PictualDelegateFactory.getImagenDelegate().readImagen(palabraVO.getImagen_4());
							imagenes[4] = PictualDelegateFactory.getImagenDelegate().readImagen(palabraVO.getImagen_5());
							imagenes[5] = PictualDelegateFactory.getImagenDelegate().readImagen(palabraVO.getImagen_6());

							//Comprobar si la palabra no tiene imagenes
							if(!PictualDelegateFactory.getPalabraDelegate().haveImages(palabraVO.getPalabra_id())){
								descargarImagenes=true;
								log.info("La palabra esta en bbdd pero no tiene imagenes. Se descargaran las imagenes");
								images = GoogleSearchImg.queryForImages(query, langLeft);
								int i=0;
								for(MyImage img: images){
									log.info("imagen encontrada");
									imagenes[i]=new ImagenVO();
									imagenes[i].setHeight(img.getHeight());
									imagenes[i].setWidth(img.getWidth());
									imagenes[i].setPath_big(img.getImgLink());
									imagenes[i].setPath_small(img.getImgThumbnail());
									log.info(i+": "+imagenes[i].getPath_big());
									i++;
								}
							}
							
							
							completo.setIdiomaVO(idiomaVO);
							completo.setDefinicionVO(definicionVO);
							completo.setPalabraVO(palabraVO);
							completo.setImagenes(imagenes);

							
							/* RECUPERA DE LA BASE DE DATOS */
							log.info("RECUPERA DE LA BASE DE DATOS");
							enDatabase=true;

							/* INSERTO EN CACHE */
							log.info("INSERTO EN CACHE");
							cache.put(cadenaParaCache, completo);
							log.info("se rellena para cache");
						}
					} catch (DAOException e) {
						log.error("mensaje: "+e.getMessage());
					}
				}else{
					imagenes[0] = new ImagenVO(query, 1);
					imagenes[1] = new ImagenVO(query, 2);
					imagenes[2] = new ImagenVO(query, 3);
					imagenes[3] = new ImagenVO(query, 4);
					imagenes[4] = new ImagenVO(query, 5);
					imagenes[5] = new ImagenVO(query, 6);
					completo.setImagenes(imagenes);

					log.debug("IMAGENES INVENTADAS: "+imagenes[0].getPath_big());
					log.debug("IMAGENES INVENTADAS: "+imagenes[0].getPath_small());
				}

				/* NO RECUPERA DATOS DE LA BASE DE DATOS */
				if(!enDatabase){		
					log.info("NO RECUPERA DATOS DE LA BASE DE DATOS");
					/* BUSCAR EN WIKI */
					log.info("BUSCAR EN WIKI");
					log.info("La palabra "+query +" no esta en la BBDD. Busco en wiki");
					cadena_wiki=WikiObtieneDatos.getData(query, langRight);

					if(!cadena_wiki.isEmpty()){
						WikiTrataDatos wtd = new WikiTrataDatos(query, cadena_wiki, langRight, langLeft);
						log.info("Los datos han sido obtenidos de wiki");
						idiomaVO = wtd.getIdiomaVO();
						definicionVO = wtd.getDefinicionVO();
						palabraVO = wtd.getPalabraVO();
						log.info("Los datos están en los VO");

						/* RECUPERA LOS DATOS DE WIKI */
						log.info("RECUPERA LOS DATOS DE WIKI");
						enWiki=true;
						/* INSERTO EN BASE DE DATOS */
						if(accesoBD.conecta()){

							log.info("Se descargaran las imagenes");
							images = GoogleSearchImg.queryForImages(query, langLeft);
							int i=0;
							for(MyImage img: images){
								log.info("imagen encontrada");
								imagenes[i]=new ImagenVO();
								imagenes[i].setHeight(img.getHeight());
								imagenes[i].setWidth(img.getWidth());
								imagenes[i].setPath_big(img.getImgLink());
								imagenes[i].setPath_small(img.getImgThumbnail());
								log.info(i+": "+imagenes[i].getPath_big());
								i++;
							}

							log.info("INSERTO EN BASE DE DATOS");
							for(ImagenVO img: imagenes){
								if(img!=null) PictualDelegateFactory.getImagenDelegate().insertImagen(img);
							}
							if(imagenes[0]!=null) palabraVO.setImagen_1(imagenes[0].getImagen_id());
							if(imagenes[1]!=null) palabraVO.setImagen_2(imagenes[1].getImagen_id());
							if(imagenes[2]!=null) palabraVO.setImagen_3(imagenes[2].getImagen_id());
							if(imagenes[3]!=null) palabraVO.setImagen_4(imagenes[3].getImagen_id());
							if(imagenes[4]!=null) palabraVO.setImagen_5(imagenes[4].getImagen_id());
							if(imagenes[5]!=null) palabraVO.setImagen_6(imagenes[5].getImagen_id());



							int palabra_id=PictualDelegateFactory.getPalabraDelegate().insertPalabra(palabraVO);
							definicionVO.setPalabra_id(palabra_id);
							idiomaVO.setPalabra_id(palabra_id);

							if(PictualDelegateFactory.getIdiomaDelegate().readIdioma(idiomaVO.getNombre(), idiomaVO.getIdioma())==null)
								PictualDelegateFactory.getIdiomaDelegate().insertIdioma(idiomaVO);
							if(PictualDelegateFactory.getDefinicionDelegate().readDefinicion(definicionVO.getPalabra_id(), definicionVO.getIdioma_origen(), definicionVO.getIdioma_destino())==null)
								PictualDelegateFactory.getDefinicionDelegate().insertDefinicion(definicionVO);
							
							nuevaPalabra=true;
							
						}else{
							imagenes[0] = new ImagenVO(query, 1);
							imagenes[1] = new ImagenVO(query, 2);
							imagenes[2] = new ImagenVO(query, 3);
							imagenes[3] = new ImagenVO(query, 4);
							imagenes[4] = new ImagenVO(query, 5);
							imagenes[5] = new ImagenVO(query, 6);
							completo.setImagenes(imagenes);

							log.debug("IMAGENES INVENTADAS: "+imagenes[0].getPath_big());
							log.debug("IMAGENES INVENTADAS: "+imagenes[0].getPath_small());
						}
						log.info(palabraVO);
						log.info(definicionVO);
						log.info(idiomaVO);

						completo = new CompletoVO();
						completo.setIdiomaVO(idiomaVO);
						completo.setDefinicionVO(definicionVO);
						completo.setPalabraVO(palabraVO);
						completo.setImagenes(imagenes);
						/* INSERTO EN CACHE */
						log.info("INSERTO EN CACHE");
						cache.put(cadenaParaCache, completo);
						log.info("se rellena para cache");

					}

					/* NO RECUPERA DATOS DE WIKI */
					log.info("NO RECUPERA DATOS EN WIKI");
					if(!enWiki){
						log.info("La palabra no esta en la wiki seleccionada");
					}
					else{
						/* NO SE HA ENCONTRADO LA PALABRA */
						log.info("NO SE HA ENCONTRADO LA PALABRA");
					}

				}
			}

			if(enWiki){
				images = DatabaseImg.getVectorImages(imagenes);
			}
			if(enDatabase){
				images = DatabaseImg.getVectorImages(imagenes);
			}
			if(enCache){
				if((completo.getImagenes()!=null)||(completo.getImagenes().length<1)){
					images = DatabaseImg.getVectorImages(completo.getImagenes());
				}
			}
			
			//AUMENTAR VISITAS
			if(accesoBD.conecta()){
				int visitas = PictualDelegateFactory.getIdiomaDelegate().aumentarVisitas(idiomaVO);
				log.info("La palabra "+query+" se ha visitado "+visitas+" veces");
			}

			log.info(idiomaVO);
			log.info(definicionVO);
			log.info(palabraVO);
			log.info(completo);

			//METER EN EL REQUEST
			request.setAttribute(RequestKeys.IMAGES, images);
			request.setAttribute(RequestKeys.IDIOMA, idiomaVO);
			request.setAttribute(RequestKeys.DEFINICION, definicionVO);
			request.setAttribute(RequestKeys.PALABRA, palabraVO);


			//SACAR ENLACES
			if(idiomaVO!=null){

				if (idiomaVO.getVerbo()!=null) {
					String conjugate = "#";
					if (langLeft.equals("en")) conjugate = "http://www.wordreference.com/conj/EnVerbs.aspv="+ query;
					if (langLeft.equals("es")) conjugate = "http://www.wordreference.com/conj/EsVerbs.asp?v="+ query;
					if (langLeft.equals("de")) conjugate = "http://www.canoo.net/services/Controller?dispatch=inflection&lang=de&input="+ query + "&features=(Cat+V)";
					if (langLeft.equals("fr")) conjugate = "http://www.wordreference.com/conj/FrVerbs.asp?v="+ query;

					request.setAttribute(RequestKeys.CONJUGATE, conjugate);
				}

				String enlace = "#";
				if(langRight.equals("en")){
					if(langLeft.equals("es")) enlace = "http://www.wordreference.com/es/en/translation.asp?spen="+query;
					if(langLeft.equals("en")) enlace = "http://www.merriam-webster.com/dictionary/"+query;
					if(langLeft.equals("de")){
						String q = query;
						q = q.replaceAll("ü", "ue");
						q = q.replaceAll("ß", "ss");
						q = q.replaceAll("ä ", "ae");
						q = q.replaceAll("ö", "oe");
						enlace = "http://es.bab.la/diccionario/aleman-ingles/"+q;
					}
					if(langLeft.equals("fr")) enlace = "http://www.wordreference.com/fren/"+query;

				}
				if(langRight.equals("es")){
					if(langLeft.equals("es")) enlace = "http://buscon.rae.es/draeI/SrvltConsulta?TIPO_BUS=3&LEMA=" + query;
					if(langLeft.equals("en")) enlace = "http://www.wordreference.com/es/en/translation.asp?spen="+query;
					if(langLeft.equals("de")) enlace = "http://dict.leo.org/esde?lp=esde&lang=de&searchLoc=0&cmpType=relaxed&sectHdr=on&spellToler=&search="+query;
					if(langLeft.equals("fr")) enlace = "http://diccionario.reverso.net/espanol-frances/"+query;
				}
				if(langRight.equals("de")){
					if(langLeft.equals("es")) enlace = "http://es.bab.la/diccionario/espanol-aleman/"+query;
					if(langLeft.equals("en")) enlace = "http://es.bab.la/diccionario/ingles-aleman/"+query;
					if(langLeft.equals("de")) enlace = "http://www.dwds.de/?woerterbuch=1&kompakt=1&sh=1&qu="+query;
					if(langLeft.equals("fr")) enlace = "http://dict.leo.org/frde?lp=frde&lang=de&searchLoc=0&cmpType=relaxed&sectHdr=on&spellToler=&search="+query;
				}
				if(langRight.equals("fr")){
					if(langLeft.equals("es")) enlace = "http://www.larousse.com/fr/dictionnaires/espagnol-francais/"+query;
					if(langLeft.equals("en")) enlace = "http://www.larousse.com/fr/dictionnaires/anglais-francais/"+query;
					if(langLeft.equals("de")) enlace = "http://www.larousse.com/fr/dictionnaires/allemand-francais/"+query;
					if(langLeft.equals("fr")) enlace = "http://www.larousse.com/fr/dictionnaires/francais/"+query;
				}
				request.setAttribute(RequestKeys.ENLACE, enlace);

				String pronunciacion = new GetPronun(query, langLeft).getPhonetic();
				if(pronunciacion==null) pronunciacion=idiomaVO.getPronunciacion();
				request.setAttribute(RequestKeys.PRONUNCIACION, pronunciacion);	

			}

			session.setAttribute(SessionKeys.QUERY, query);
			session.setAttribute(SessionKeys.FROM, langLeft);
			session.setAttribute(SessionKeys.TO, langRight);
			//			System.out.println("en session: "+session.getAttribute(SessionKeys.FROM));
			//			System.out.println("en session: "+session.getAttribute(SessionKeys.TO));

			//			MySQLDAOFactory.closeCsonnection();				
		}

		long t2 = System.currentTimeMillis();
		long t = (t2 - t1)/1000; // en segundos
		log.info("***timeSearch: LA BUSQUEDA de "+query+" TARDA " + t + " SEGUNDOS");
		if(nuevaPalabra) Mail.enviar(query, langLeft, langRight, t);
		return mapping.findForward("success");

	}
}
